/**
 * 文件处理工具类
 * 提供文件类型检测、大小校验、格式转换、预览等功能
 */

/**
 * 文件类型枚举
 */
export enum FileType {
  IMAGE = 'image',
  VIDEO = 'video',
  AUDIO = 'audio',
  DOCUMENT = 'document',
  ARCHIVE = 'archive',
  CODE = 'code',
  UNKNOWN = 'unknown'
}

/**
 * 文件信息接口
 */
export interface FileInfo {
  name: string;
  size: number;
  type: string;
  lastModified: number;
  fileType: FileType;
  extension: string;
  mimeType: string;
  isImage: boolean;
  isVideo: boolean;
  isAudio: boolean;
  isDocument: boolean;
  isArchive: boolean;
  isCode: boolean;
}

/**
 * 文件校验结果接口
 */
export interface FileValidationResult {
  isValid: boolean;
  message: string;
  errors: string[];
  warnings: string[];
}

/**
 * 批量文件校验结果接口
 */
export interface BatchFileValidationResult {
  isValid: boolean;
  message: string;
  validFiles: FileInfo[];
  invalidFiles: Array<{
    file: FileInfo;
    reason: string;
  }>;
  totalCount: number;
  validCount: number;
  invalidCount: number;
  totalSize: number;
  validSize: number;
  invalidSize: number;
}

/**
 * 文件大小配置
 */
export interface FileSizeConfig {
  maxSize: number;           // 最大文件大小（字节）
  minSize: number;           // 最小文件大小（字节）
  maxTotalSize: number;      // 总文件大小限制（字节）
  maxFileCount: number;      // 最大文件数量
}

/**
 * 文件类型配置
 */
export interface FileTypeConfig {
  allowedTypes: string[];     // 允许的文件类型
  allowedExtensions: string[]; // 允许的文件扩展名
  blockedTypes: string[];     // 禁止的文件类型
  blockedExtensions: string[]; // 禁止的文件扩展名
}

/**
 * 文件类型规则配置
 */
export const FILE_TYPE_RULES: Record<string, { extensions: string[]; mimeTypes: string[]; description: string }> = {
  // 图片类型
  IMAGE_JPEG: {
    extensions: ['jpg', 'jpeg'],
    mimeTypes: ['image/jpeg'],
    description: 'JPEG图片'
  },
  IMAGE_PNG: {
    extensions: ['png'],
    mimeTypes: ['image/png'],
    description: 'PNG图片'
  },
  IMAGE_GIF: {
    extensions: ['gif'],
    mimeTypes: ['image/gif'],
    description: 'GIF图片'
  },
  IMAGE_WEBP: {
    extensions: ['webp'],
    mimeTypes: ['image/webp'],
    description: 'WebP图片'
  },
  IMAGE_SVG: {
    extensions: ['svg'],
    mimeTypes: ['image/svg+xml'],
    description: 'SVG图片'
  },
  IMAGE_BMP: {
    extensions: ['bmp'],
    mimeTypes: ['image/bmp'],
    description: 'BMP图片'
  },
  IMAGE_ICO: {
    extensions: ['ico'],
    mimeTypes: ['image/x-icon', 'image/vnd.microsoft.icon'],
    description: 'ICO图标'
  },

  // 视频类型
  VIDEO_MP4: {
    extensions: ['mp4'],
    mimeTypes: ['video/mp4'],
    description: 'MP4视频'
  },
  VIDEO_AVI: {
    extensions: ['avi'],
    mimeTypes: ['video/x-msvideo'],
    description: 'AVI视频'
  },
  VIDEO_MOV: {
    extensions: ['mov'],
    mimeTypes: ['video/quicktime'],
    description: 'MOV视频'
  },
  VIDEO_WMV: {
    extensions: ['wmv'],
    mimeTypes: ['video/x-ms-wmv'],
    description: 'WMV视频'
  },
  VIDEO_WEBM: {
    extensions: ['webm'],
    mimeTypes: ['video/webm'],
    description: 'WebM视频'
  },

  // 音频类型
  AUDIO_MP3: {
    extensions: ['mp3'],
    mimeTypes: ['audio/mpeg'],
    description: 'MP3音频'
  },
  AUDIO_WAV: {
    extensions: ['wav'],
    mimeTypes: ['audio/wav'],
    description: 'WAV音频'
  },
  AUDIO_OGG: {
    extensions: ['ogg'],
    mimeTypes: ['audio/ogg'],
    description: 'OGG音频'
  },
  AUDIO_AAC: {
    extensions: ['aac'],
    mimeTypes: ['audio/aac'],
    description: 'AAC音频'
  },

  // 文档类型
  DOCUMENT_PDF: {
    extensions: ['pdf'],
    mimeTypes: ['application/pdf'],
    description: 'PDF文档'
  },
  DOCUMENT_DOC: {
    extensions: ['doc'],
    mimeTypes: ['application/msword'],
    description: 'Word文档'
  },
  DOCUMENT_DOCX: {
    extensions: ['docx'],
    mimeTypes: ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
    description: 'Word文档'
  },
  DOCUMENT_XLS: {
    extensions: ['xls'],
    mimeTypes: ['application/vnd.ms-excel'],
    description: 'Excel文档'
  },
  DOCUMENT_XLSX: {
    extensions: ['xlsx'],
    mimeTypes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
    description: 'Excel文档'
  },
  DOCUMENT_PPT: {
    extensions: ['ppt'],
    mimeTypes: ['application/vnd.ms-powerpoint'],
    description: 'PowerPoint文档'
  },
  DOCUMENT_PPTX: {
    extensions: ['pptx'],
    mimeTypes: ['application/vnd.openxmlformats-officedocument.presentationml.presentation'],
    description: 'PowerPoint文档'
  },
  DOCUMENT_TXT: {
    extensions: ['txt'],
    mimeTypes: ['text/plain'],
    description: '文本文件'
  },
  DOCUMENT_RTF: {
    extensions: ['rtf'],
    mimeTypes: ['application/rtf'],
    description: 'RTF文档'
  },

  // 压缩文件类型
  ARCHIVE_ZIP: {
    extensions: ['zip'],
    mimeTypes: ['application/zip'],
    description: 'ZIP压缩包'
  },
  ARCHIVE_RAR: {
    extensions: ['rar'],
    mimeTypes: ['application/x-rar-compressed'],
    description: 'RAR压缩包'
  },
  ARCHIVE_7Z: {
    extensions: ['7z'],
    mimeTypes: ['application/x-7z-compressed'],
    description: '7Z压缩包'
  },
  ARCHIVE_TAR: {
    extensions: ['tar'],
    mimeTypes: ['application/x-tar'],
    description: 'TAR压缩包'
  },

  // 代码文件类型
  CODE_JS: {
    extensions: ['js'],
    mimeTypes: ['application/javascript', 'text/javascript'],
    description: 'JavaScript文件'
  },
  CODE_TS: {
    extensions: ['ts'],
    mimeTypes: ['application/typescript', 'text/typescript'],
    description: 'TypeScript文件'
  },
  CODE_CSS: {
    extensions: ['css'],
    mimeTypes: ['text/css'],
    description: 'CSS文件'
  },
  CODE_HTML: {
    extensions: ['html', 'htm'],
    mimeTypes: ['text/html'],
    description: 'HTML文件'
  },
  CODE_JSON: {
    extensions: ['json'],
    mimeTypes: ['application/json'],
    description: 'JSON文件'
  },
  CODE_XML: {
    extensions: ['xml'],
    mimeTypes: ['application/xml', 'text/xml'],
    description: 'XML文件'
  }
};

/**
 * 获取文件扩展名
 * @param filename 文件名
 * @returns 扩展名（小写）
 */
export function getFileExtension(filename: string): string {
  if (!filename || typeof filename !== 'string') {
    return '';
  }
  
  const lastDotIndex = filename.lastIndexOf('.');
  if (lastDotIndex === -1 || lastDotIndex === filename.length - 1) {
    return '';
  }
  
  return filename.substring(lastDotIndex + 1).toLowerCase();
}

/**
 * 获取文件MIME类型
 * @param file 文件对象
 * @returns MIME类型
 */
export function getFileMimeType(file: File): string {
  return file.type || '';
}

/**
 * 检测文件类型
 * @param file 文件对象
 * @returns 文件类型
 */
export function detectFileType(file: File): FileType {
  const extension = getFileExtension(file.name);
  const mimeType = getFileMimeType(file).toLowerCase();
  
  // 图片类型检测
  if (mimeType.startsWith('image/') || 
      ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico'].includes(extension)) {
    return FileType.IMAGE;
  }
  
  // 视频类型检测
  if (mimeType.startsWith('video/') || 
      ['mp4', 'avi', 'mov', 'wmv', 'webm', 'flv', 'mkv'].includes(extension)) {
    return FileType.VIDEO;
  }
  
  // 音频类型检测
  if (mimeType.startsWith('audio/') || 
      ['mp3', 'wav', 'ogg', 'aac', 'flac', 'm4a'].includes(extension)) {
    return FileType.AUDIO;
  }
  
  // 文档类型检测
  if (mimeType.includes('pdf') || mimeType.includes('document') || mimeType.includes('text') ||
      ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'rtf'].includes(extension)) {
    return FileType.DOCUMENT;
  }
  
  // 压缩文件类型检测
  if (mimeType.includes('zip') || mimeType.includes('rar') || mimeType.includes('7z') ||
      ['zip', 'rar', '7z', 'tar', 'gz', 'bz2'].includes(extension)) {
    return FileType.ARCHIVE;
  }
  
  // 代码文件类型检测
  if (mimeType.includes('javascript') || mimeType.includes('typescript') || mimeType.includes('css') ||
      ['js', 'ts', 'css', 'html', 'htm', 'json', 'xml', 'py', 'java', 'cpp', 'c'].includes(extension)) {
    return FileType.CODE;
  }
  
  return FileType.UNKNOWN;
}

/**
 * 获取文件信息
 * @param file 文件对象
 * @returns 文件信息
 */
export function getFileInfo(file: File): FileInfo {
  const extension = getFileExtension(file.name);
  const mimeType = getFileMimeType(file);
  const fileType = detectFileType(file);
  
  return {
    name: file.name,
    size: file.size,
    type: mimeType,
    lastModified: file.lastModified,
    fileType,
    extension,
    mimeType,
    isImage: fileType === FileType.IMAGE,
    isVideo: fileType === FileType.VIDEO,
    isAudio: fileType === FileType.AUDIO,
    isDocument: fileType === FileType.DOCUMENT,
    isArchive: fileType === FileType.ARCHIVE,
    isCode: fileType === FileType.CODE
  };
}

/**
 * 校验单个文件
 * @param file 文件对象
 * @param sizeConfig 大小配置
 * @param typeConfig 类型配置
 * @returns 校验结果
 */
export function validateFile(
  file: File, 
  sizeConfig?: Partial<FileSizeConfig>, 
  typeConfig?: Partial<FileTypeConfig>
): FileValidationResult {
  const errors: string[] = [];
  const warnings: string[] = [];
  
  // 基础文件检查
  if (!file) {
    return {
      isValid: false,
      message: '文件不存在',
      errors: ['文件不存在'],
      warnings: []
    };
  }
  
  const fileInfo = getFileInfo(file);
  
  // 大小检查
  if (sizeConfig) {
    if (sizeConfig.maxSize && file.size > sizeConfig.maxSize) {
      errors.push(`文件大小超过限制，最大允许 ${formatFileSize(sizeConfig.maxSize)}`);
    }
    
    if (sizeConfig.minSize && file.size < sizeConfig.minSize) {
      errors.push(`文件大小不足，最小需要 ${formatFileSize(sizeConfig.minSize)}`);
    }
  }
  
  // 类型检查
  if (typeConfig) {
    // 允许的类型检查
    if (typeConfig.allowedTypes && typeConfig.allowedTypes.length > 0) {
      const isAllowedType = typeConfig.allowedTypes.some(type => 
        fileInfo.mimeType.includes(type) || fileInfo.fileType === type
      );
      if (!isAllowedType) {
        errors.push(`文件类型不在允许列表中`);
      }
    }
    
    // 允许的扩展名检查
    if (typeConfig.allowedExtensions && typeConfig.allowedExtensions.length > 0) {
      if (!typeConfig.allowedExtensions.includes(fileInfo.extension)) {
        errors.push(`文件扩展名不在允许列表中`);
      }
    }
    
    // 禁止的类型检查
    if (typeConfig.blockedTypes && typeConfig.blockedTypes.length > 0) {
      const isBlockedType = typeConfig.blockedTypes.some(type => 
        fileInfo.mimeType.includes(type) || fileInfo.fileType === type
      );
      if (isBlockedType) {
        errors.push(`文件类型在禁止列表中`);
      }
    }
    
    // 禁止的扩展名检查
    if (typeConfig.blockedExtensions && typeConfig.blockedExtensions.length > 0) {
      if (typeConfig.blockedExtensions.includes(fileInfo.extension)) {
        errors.push(`文件扩展名在禁止列表中`);
      }
    }
  }
  
  // 文件名检查
  if (!file.name || file.name.trim().length === 0) {
    errors.push('文件名不能为空');
  }
  
  // 文件大小警告
  if (file.size > 50 * 1024 * 1024) { // 50MB
    warnings.push('文件较大，可能影响上传速度');
  }
  
  return {
    isValid: errors.length === 0,
    message: errors.length === 0 ? '文件校验通过' : '文件校验失败',
    errors,
    warnings
  };
}

/**
 * 批量文件校验
 * @param files 文件数组
 * @param sizeConfig 大小配置
 * @param typeConfig 类型配置
 * @returns 批量校验结果
 */
export function validateBatchFiles(
  files: File[], 
  sizeConfig?: Partial<FileSizeConfig>, 
  typeConfig?: Partial<FileTypeConfig>
): BatchFileValidationResult {
  const validFiles: FileInfo[] = [];
  const invalidFiles: Array<{ file: FileInfo; reason: string }> = [];
  let totalSize = 0;
  let validSize = 0;
  let invalidSize = 0;
  
  for (const file of files) {
    const fileInfo = getFileInfo(file);
    totalSize += file.size;
    
    const validation = validateFile(file, sizeConfig, typeConfig);
    
    if (validation.isValid) {
      validFiles.push(fileInfo);
      validSize += file.size;
    } else {
      invalidFiles.push({
        file: fileInfo,
        reason: validation.errors.join(', ')
      });
      invalidSize += file.size;
    }
  }
  
  // 总大小检查
  if (sizeConfig?.maxTotalSize && totalSize > sizeConfig.maxTotalSize) {
    return {
      isValid: false,
      message: `总文件大小超过限制，最大允许 ${formatFileSize(sizeConfig.maxTotalSize)}`,
      validFiles: [],
      invalidFiles: files.map(file => ({
        file: getFileInfo(file),
        reason: '总文件大小超过限制'
      })),
      totalCount: files.length,
      validCount: 0,
      invalidCount: files.length,
      totalSize,
      validSize: 0,
      invalidSize: totalSize
    };
  }
  
  // 文件数量检查
  if (sizeConfig?.maxFileCount && files.length > sizeConfig.maxFileCount) {
    return {
      isValid: false,
      message: `文件数量超过限制，最大允许 ${sizeConfig.maxFileCount} 个`,
      validFiles: [],
      invalidFiles: files.map(file => ({
        file: getFileInfo(file),
        reason: '文件数量超过限制'
      })),
      totalCount: files.length,
      validCount: 0,
      invalidCount: files.length,
      totalSize,
      validSize: 0,
      invalidSize: totalSize
    };
  }
  
  return {
    isValid: invalidFiles.length === 0,
    message: invalidFiles.length === 0 ? '所有文件校验通过' : `发现 ${invalidFiles.length} 个无效文件`,
    validFiles,
    invalidFiles,
    totalCount: files.length,
    validCount: validFiles.length,
    invalidCount: invalidFiles.length,
    totalSize,
    validSize,
    invalidSize
  };
}

/**
 * 格式化文件大小
 * @param bytes 字节数
 * @param decimals 小数位数
 * @returns 格式化后的文件大小
 */
export function formatFileSize(bytes: number, decimals: number = 2): string {
  if (bytes === 0) return '0 Bytes';
  
  const k = 1024;
  const dm = decimals < 0 ? 0 : decimals;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
  
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  
  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

/**
 * 检查文件是否为图片
 * @param file 文件对象
 * @returns 是否为图片
 */
export function isImageFile(file: File): boolean {
  return detectFileType(file) === FileType.IMAGE;
}

/**
 * 检查文件是否为视频
 * @param file 文件对象
 * @returns 是否为视频
 */
export function isVideoFile(file: File): boolean {
  return detectFileType(file) === FileType.VIDEO;
}

/**
 * 检查文件是否为音频
 * @param file 文件对象
 * @returns 是否为音频
 */
export function isAudioFile(file: File): boolean {
  return detectFileType(file) === FileType.AUDIO;
}

/**
 * 检查文件是否为文档
 * @param file 文件对象
 * @returns 是否为文档
 */
export function isDocumentFile(file: File): boolean {
  return detectFileType(file) === FileType.DOCUMENT;
}

/**
 * 检查文件是否为压缩包
 * @param file 文件对象
 * @returns 是否为压缩包
 */
export function isArchiveFile(file: File): boolean {
  return detectFileType(file) === FileType.ARCHIVE;
}

/**
 * 检查文件是否为代码文件
 * @param file 文件对象
 * @returns 是否为代码文件
 */
export function isCodeFile(file: File): boolean {
  return detectFileType(file) === FileType.CODE;
}

/**
 * 生成文件预览URL
 * @param file 文件对象
 * @returns 预览URL
 */
export function createFilePreviewUrl(file: File): string {
  return URL.createObjectURL(file);
}

/**
 * 释放文件预览URL
 * @param url 预览URL
 */
export function revokeFilePreviewUrl(url: string): void {
  URL.revokeObjectURL(url);
}

/**
 * 读取文件内容为文本
 * @param file 文件对象
 * @returns Promise<string>
 */
export function readFileAsText(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = () => reject(reader.error);
    reader.readAsText(file);
  });
}

/**
 * 读取文件内容为DataURL
 * @param file 文件对象
 * @returns Promise<string>
 */
export function readFileAsDataURL(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = () => reject(reader.error);
    reader.readAsDataURL(file);
  });
}

/**
 * 读取文件内容为ArrayBuffer
 * @param file 文件对象
 * @returns Promise<ArrayBuffer>
 */
export function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as ArrayBuffer);
    reader.onerror = () => reject(reader.error);
    reader.readAsArrayBuffer(file);
  });
}

/**
 * 获取图片尺寸
 * @param file 图片文件
 * @returns Promise<{width: number, height: number}>
 */
export function getImageDimensions(file: File): Promise<{ width: number; height: number }> {
  return new Promise((resolve, reject) => {
    if (!isImageFile(file)) {
      reject(new Error('文件不是图片类型'));
      return;
    }
    
    const img = new Image();
    img.onload = () => {
      resolve({ width: img.width, height: img.height });
    };
    img.onerror = () => {
      reject(new Error('无法加载图片'));
    };
    img.src = createFilePreviewUrl(file);
  });
}

/**
 * 压缩图片
 * @param file 图片文件
 * @param quality 压缩质量 (0-1)
 * @param maxWidth 最大宽度
 * @param maxHeight 最大高度
 * @returns Promise<Blob>
 */
export function compressImage(
  file: File, 
  quality: number = 0.8, 
  maxWidth: number = 1920, 
  maxHeight: number = 1080
): Promise<Blob> {
  return new Promise((resolve, reject) => {
    if (!isImageFile(file)) {
      reject(new Error('文件不是图片类型'));
      return;
    }
    
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const img = new Image();
    
    img.onload = () => {
      // 计算压缩后的尺寸
      let { width, height } = img;
      
      if (width > maxWidth || height > maxHeight) {
        const ratio = Math.min(maxWidth / width, maxHeight / height);
        width *= ratio;
        height *= ratio;
      }
      
      canvas.width = width;
      canvas.height = height;
      
      // 绘制压缩后的图片
      ctx?.drawImage(img, 0, 0, width, height);
      
      canvas.toBlob(
        (blob) => {
          if (blob) {
            resolve(blob);
          } else {
            reject(new Error('图片压缩失败'));
          }
        },
        file.type,
        quality
      );
    };
    
    img.onerror = () => {
      reject(new Error('无法加载图片'));
    };
    
    img.src = createFilePreviewUrl(file);
  });
}

/**
 * 文件工具类
 */
export class FileUtils {
  /**
   * 获取支持的文件类型列表
   * @returns 支持的文件类型
   */
  static getSupportedFileTypes(): string[] {
    return Object.keys(FILE_TYPE_RULES);
  }
  
  /**
   * 根据扩展名获取文件类型规则
   * @param extension 扩展名
   * @returns 文件类型规则
   */
  static getFileTypeRuleByExtension(extension: string): any {
    for (const [key, rule] of Object.entries(FILE_TYPE_RULES)) {
      if (rule.extensions.includes(extension.toLowerCase())) {
        return { key, ...rule };
      }
    }
    return null;
  }
  
  /**
   * 根据MIME类型获取文件类型规则
   * @param mimeType MIME类型
   * @returns 文件类型规则
   */
  static getFileTypeRuleByMimeType(mimeType: string): any {
    for (const [key, rule] of Object.entries(FILE_TYPE_RULES)) {
      if (rule.mimeTypes.includes(mimeType.toLowerCase())) {
        return { key, ...rule };
      }
    }
    return null;
  }
  
  /**
   * 生成文件下载链接
   * @param file 文件对象
   * @param filename 下载文件名
   * @returns 下载链接
   */
  static createDownloadLink(file: File, filename?: string): string {
    const url = createFilePreviewUrl(file);
    const link = document.createElement('a');
    link.href = url;
    link.download = filename || file.name;
    return url;
  }
  
  /**
   * 触发文件下载
   * @param file 文件对象
   * @param filename 下载文件名
   */
  static downloadFile(file: File, filename?: string): void {
    const url = createFilePreviewUrl(file);
    const link = document.createElement('a');
    link.href = url;
    link.download = filename || file.name;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    revokeFilePreviewUrl(url);
  }
}
